﻿using System;
using System.Collections.Generic;
using Iesi.Collections.Generic;
using TestBat.IModels.Domain;
using TestBat.IModels.Models;
using TestBat.IModels.Repositories;
using TestBat.Models.Attributes;
using TestBat.Models.Exceptions;
using System.Linq;

namespace TestBat.Models.Models
{
    public class TestTaskModel : Model, ITestTaskModel
    {
        public TestTaskModel(ITestTaskRepository testTaskRepository)
        {
            this.testTaskRepository = testTaskRepository;
        }

        /// <summary>
        /// 
        /// </summary>
        /// <param name="schedule">mustn't be null</param>
        /// <param name="trainee">can be null</param>
        /// <param name="nonGradedOnly"></param>
        /// <returns></returns>
        [Conversation]
        public IList<ITestTask> GetByReferences(ISchedule schedule, ITrainee trainee, bool nonGradedOnly)
        {
            // HACK, TODO: should be done through a HQL query or by using the criteria API
            IList<ITestTask> selected = new List<ITestTask>();
            ISet<ITest> tests = schedule.Tests;
            foreach (ITest test in tests)
                if (test.IsClosed && (trainee == null || test.Trainee == trainee)) // only grade closed tests
                {
                    ISet<ITestTask> testTasks = test.TestTasks;
                    foreach (ITestTask testTask in testTasks)
                        if (testTask.Solution != null && testTask.Solution is IManualGradeSolution && (!nonGradedOnly || !testTask.Solution.IsGraded))
                            selected.Add(testTask);
                }

            return selected;
        }

        /// <summary>
        /// grade a test-task
        /// </summary>
        /// <param name="testTask">the test-task to grade mustn't be null; the referenced task should be manually appraisable; solution must be present</param>
        /// <param name="percent">Percentage correct, must be between 0 and 100</param>
        [Conversation]
        public void Grade(ITestTask testTask, int percent)
        {
            // HACK: shouldn't rely on casting and an ifs
            if (testTask is ITestEssayTask)
            {
                if (testTask.Solution == null || !(testTask.Solution is IEssaySolution))
                    throw new BusinessException("Can't grade testtask", new ArgumentException("Invalid solution for essaytask"));

                IEssaySolution solution = testTask.Solution as IEssaySolution;
                solution.Percentage = percent;

                testTaskRepository.MakePersistent(testTask);
            }
            else
            {
                throw new BusinessException("Can't grade testtask", new ArgumentException("Not manually appraisable task"));
            }
        }

        [Conversation]
        public IList<ITestTask> Get(ITest test)
        {
            return (from tt in test.TestTasks select tt).ToList<ITestTask>();
        }

        [Conversation]
        public ITestTask GetByID(Guid ID)
        {
            return testTaskRepository.GetByID(ID);
        }

        [Conversation(ConversationEndMode.CommitAndContinue)]
        public void SaveAll()
        {
        }

        private readonly ITestTaskRepository testTaskRepository;
    }
}
